package com.googlecode.jsonld4j.context;

import static com.googlecode.jsonld4j.Keywords.*;

import java.io.IOException;
import java.util.Iterator;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.googlecode.jsonld4j.ContainerType;
import com.googlecode.jsonld4j.util.IOUtil;

public class ContextBuilder {
	/**
	 * Create a Context from an external document.
	 * 
	 * @param url
	 *            URL of the external document
	 * @return Context instance
	 * @throws IOException
	 * @throws JSONException
	 */
	public static Context createContext(String url) throws IOException,
			JSONException {
		JSONObject json = new JSONObject(IOUtil.readAsString(url));
		Object jcontext = json.get(CONTEXT);
		if (jcontext == null)
			return null;
		if (jcontext instanceof String) {
			return createContext((String) jcontext);
		}
		if (jcontext instanceof JSONObject) {
			Context ctx = createContext((JSONObject) jcontext);
			ctx.setSourceURL(url);
			return ctx;
		}
		if (jcontext instanceof JSONArray) {
			Context ctx = createContext((JSONArray) jcontext);
			ctx.setSourceURL(url);
			return ctx;
		}
		return null;
	}

	public static Context createContext(JSONObject jcontext)
			throws JSONException {
		Context context = new Context();
		Iterator keysIt = jcontext.keys();
		while (keysIt.hasNext()) {
			String key = (String) keysIt.next();
			if (key.equals(VOCAB)) {
				context.setBaseURI(jcontext.getString(key));
			} 
			else {
				Object o = jcontext.get(key);
				if (o instanceof String) {
					context.set(key, (String) o);
				} else if (o instanceof JSONObject) {
					JSONObject v = (JSONObject) o;
					if (v.has(ID)) {
						context.setId(key, v.optString(ID));
					}
					if (v.has(TYPE)) {
						context.setType(key, v.optString(TYPE));
					}
					if (v.has(LANGUAGE)) {
						context.setLanguage(key, v.optString(LANGUAGE));
					}
					if (v.has(CONTAINER)) {
						context.setContainerType(
								key,
								Enum.valueOf(ContainerType.class,
										v.optString(CONTAINER)));
					}
				}
			}
		}
		return context;
	}

	public static Context createContext(JSONArray jcontexts)
			throws JSONException, IOException {
		Context context = null;
		for (int i = 0; i < jcontexts.length(); i++) {
			Object child = jcontexts.get(i);
			Context childContext = null;
			if (child instanceof String) {
				childContext = createContext((String) child);
			} else if (child instanceof JSONArray) {
				childContext = createContext((JSONArray) child);
			} else if (child instanceof JSONObject) {
				childContext = createContext((JSONObject) child);
			}
			if (context == null)
				context = childContext;
			else
				context = context.merge(childContext);
		}
		return context;
	}
	
	
	public static Context createContext(Object o)
			throws JSONException, IOException {
		if (o instanceof String)
			return createContext((String)o);
		if (o instanceof JSONObject)
			return createContext((JSONObject)o);
		if (o instanceof JSONArray)
			return createContext((JSONArray)o);
		return null;
	}
}
